/*
 * # iohao.com . 渔民小镇
 * Copyright (C) 2021 - 2022 double joker （262610965@qq.com） . All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.iohao.game.simulation.client.socket;

import com.alibaba.fastjson2.JSON;
import com.iohao.game.action.skeleton.core.CmdKit;
import com.iohao.game.action.skeleton.core.DataCodecKit;
import com.iohao.game.action.skeleton.core.DevConfig;
import com.iohao.game.bolt.broker.client.external.bootstrap.ExternalKit;
import com.iohao.game.bolt.broker.client.external.bootstrap.message.ExternalMessage;
import com.iohao.game.common.kit.ProtoKit;
import com.iohao.game.simulation.client.data.ActionDataManager;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldDefaults;
import org.noear.solon.core.message.Message;

import java.util.Map;

/**
 * 模拟客户到的对外协议
 *
 * @author 渔民小镇
 * @date 2022-11-01
 */
@Getter
@Setter
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ClientExternalMessage {
    /** 业务路由（高16为主, 低16为子） */
    int cmdMerge;

    /**
     * 响应码。
     * <pre>
     *     从字段精简的角度，我们不可能每次响应都带上完整的异常信息给客户端排查问题，
     *     因此，我们会定义一些响应码，通过编号进行网络传输，方便客户端定位问题。
     *
     *     0:成功
     *     !=0: 表示有错误
     * </pre>
     */
    int responseStatus;
    /** 验证信息（错误消息、异常消息） */
    String validMsg;

    String data;

    public ExternalMessage toExternalMessage() {
        Map<Integer, Class<?>> actionInputClassMap = ActionDataManager.me().getActionInputClassMap();
        Class<?> aClass = actionInputClassMap.get(this.cmdMerge);

        int cmd = CmdKit.getCmd(this.cmdMerge);
        int subCmd = CmdKit.getSubCmd(this.cmdMerge);

        Object objectData = getObject(aClass);
        byte[] bytes = DataCodecKit.encode(objectData);

        ExternalMessage externalMessage = ExternalKit.createExternalMessage(cmd, subCmd);
        externalMessage.setCmdMerge(this.cmdMerge);
        externalMessage.setData(bytes);

        return externalMessage;
    }

    private Object getObject(Class<?> aClass) {

//        String notReturnStr = "void";
//        if (notReturnStr.equals(aClass.getName())) {
//            return null;
//        }

        return JSON.parseObject(this.data, aClass);
    }

    public static ClientExternalMessage convert(ExternalMessage externalMessage) {
        int cmdMerge = externalMessage.getCmdMerge();
        Class<?> aClass = DevConfig.me().getCmdDataClass(cmdMerge);
        Object objectData = ProtoKit.parseProtoByte(externalMessage.getData(), aClass);
        String jsonString = JSON.toJSONString(objectData);

        ClientExternalMessage clientExternalMessage = new ClientExternalMessage();
        clientExternalMessage.cmdMerge = cmdMerge;
        clientExternalMessage.responseStatus = externalMessage.getResponseStatus();
        clientExternalMessage.validMsg = externalMessage.getValidMsg();
        clientExternalMessage.data = jsonString;

        return clientExternalMessage;
    }

    public String toJson() {
        return JSON.toJSONString(this);
    }

    public static ClientExternalMessage parse(Message message) {
        String json = message.bodyAsString();
        return JSON.parseObject(json, ClientExternalMessage.class);
    }
}
